package cn.rocksolid.sport.security.service.impl;

import cn.rocksolid.sport.common.C;
import cn.rocksolid.sport.common.Constant.AccessType;
import cn.rocksolid.sport.common.Constant.ShiroConst;
import cn.rocksolid.sport.common.error.RSE;
import cn.rocksolid.sport.common.utils.AssertUtils;
import cn.rocksolid.sport.common.utils.CodecUtils;
import cn.rocksolid.sport.security.dao.CredentialDao;
import cn.rocksolid.sport.security.entity.CredentialEntity;
import cn.rocksolid.sport.security.service.CredentialService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * System credential service implementation
 *
 * @author Axl Zhao
 * @email axl.zhao@163.com
 */
@Service
public class CredentialServiceImpl extends ServiceImpl<CredentialDao, CredentialEntity> implements CredentialService {

  private CredentialEntity getCredential(final String id, final AccessType accessType) {
    return getOne(new QueryWrapper<CredentialEntity>().eq(C.ID.f, id).eq(C.ACCESS_TYPE.f, accessType));
  }

  @Override
  public void verify(final String id, final AccessType accessType, final String credential) {
    CredentialEntity ce = getCredential(id, accessType);
    AssertUtils.isNotNull(ce, RSE.PWD_MISMATCH);
    AssertUtils.isNotBlank(ce.getCredential(), RSE.PWD_MISMATCH);
    AssertUtils.isNotBlank(ce.getSalt(), RSE.PWD_MISMATCH);
    AssertUtils.isTrue(
            StringUtils.equals(ce.getCredential(), CodecUtils.aes3encrypt(CodecUtils.md5(credential), ce.getSalt())),
            RSE.PWD_MISMATCH);
  }

  @Override
  @Transactional(rollbackFor = Exception.class)
  public void refresh(final String id, final AccessType accessType, final String credential) {
    CredentialEntity ce = getCredential(id, accessType);
    boolean toBeInit = false;
    if (null == ce) {
      ce = new CredentialEntity();
      toBeInit = true;
    }
    ce.setId(id);
    ce.setAccessType(accessType);
    ce.setSalt(RandomStringUtils.randomAlphanumeric(ShiroConst.SALT_LEN));
    ce.setCredential(CodecUtils.aes3encrypt(CodecUtils.md5(credential), ce.getSalt()));
    if (toBeInit) {
      save(ce);
    } else {
      updateById(ce);
    }
  }
}
